home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / MeshFromOBJ / MeshFromObj.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  31.1 KB  |  694 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: MeshFromOBJ.cpp
  3. //
  4. // This sample shows how an ID3DXMesh object can be created from mesh data stored in an 
  5. // .obj file. It's convenient to use .x files when working with ID3DXMesh objects since 
  6. // D3DX can create and fill an ID3DXMesh object directly from an .x file; however, itÆs 
  7. // also easy to initialize an ID3DXMesh object with data gathered from any file format 
  8. // or memory resource.
  9. //
  10. // Copyright (c) Microsoft Corporation. All rights reserved.
  11. //--------------------------------------------------------------------------------------
  12. #include "dxstdafx.h"
  13. #include "resource.h"
  14. #include "meshloader.h"
  15.  
  16. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  17. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  18.  
  19.  
  20.  
  21. //--------------------------------------------------------------------------------------
  22. // Global variables
  23. //--------------------------------------------------------------------------------------
  24. ID3DXFont*                   g_pFont = NULL;          // Font for drawing text
  25. ID3DXSprite*                 g_pTextSprite = NULL;    // Sprite for batching draw text calls
  26. ID3DXEffect*                 g_pEffect = NULL;        // D3DX effect interface
  27. CModelViewerCamera           g_Camera;                // A model viewing camera
  28. bool                         g_bShowHelp = true;      // If true, it renders the UI control text
  29. CDXUTDialog                  g_HUD;                   // dialog for standard controls
  30. CDXUTDialog                  g_SampleUI;              // dialog for sample specific controls
  31.  
  32. CMeshLoader                  g_MeshLoader;            // Loads a mesh from an .obj file
  33.  
  34. WCHAR                        g_strFileSaveMessage[MAX_PATH] = {0}; // Text indicating file write success/failure
  35.  
  36.  
  37. //--------------------------------------------------------------------------------------
  38. // Effect parameter handles
  39. //--------------------------------------------------------------------------------------
  40. D3DXHANDLE g_hAmbient = NULL;
  41. D3DXHANDLE g_hDiffuse = NULL;
  42. D3DXHANDLE g_hSpecular = NULL;
  43. D3DXHANDLE g_hOpacity = NULL;
  44. D3DXHANDLE g_hSpecularPower = NULL;
  45. D3DXHANDLE g_hLightColor = NULL;
  46. D3DXHANDLE g_hLightPosition = NULL;
  47. D3DXHANDLE g_hCameraPosition = NULL;
  48. D3DXHANDLE g_hTexture = NULL;      
  49. D3DXHANDLE g_hTime = NULL;
  50. D3DXHANDLE g_hWorld = NULL;
  51. D3DXHANDLE g_hWorldViewProjection = NULL;
  52.  
  53.  
  54. //--------------------------------------------------------------------------------------
  55. // UI control IDs
  56. //--------------------------------------------------------------------------------------
  57. #define IDC_STATIC              -1
  58. #define IDC_TOGGLEFULLSCREEN    1
  59. #define IDC_TOGGLEREF           3
  60. #define IDC_CHANGEDEVICE        4
  61. #define IDC_SUBSET              5
  62. #define IDC_SAVETOX             6
  63.  
  64.  
  65.  
  66. //--------------------------------------------------------------------------------------
  67. // Forward declarations 
  68. //--------------------------------------------------------------------------------------
  69. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  70. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  71. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  72. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  73. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  74. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  75. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  76. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  77. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  78. void    CALLBACK OnLostDevice();
  79. void    CALLBACK OnDestroyDevice();
  80.  
  81. void    InitApp();
  82. void    RenderText();
  83. void    RenderSubset( UINT iSubset );
  84. void    SaveMeshToXFile();
  85.  
  86. //--------------------------------------------------------------------------------------
  87. // Entry point to the program. Initializes everything and goes into a message processing 
  88. // loop. Idle time is used to render the scene.
  89. //--------------------------------------------------------------------------------------
  90. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  91. {
  92.     // Set the callback functions. These functions allow the sample framework to notify
  93.     // the application about device changes, user input, and windows messages.  The 
  94.     // callbacks are optional so you need only set callbacks for events you're interested 
  95.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  96.     // framework won't be able to reset your device since the application must first 
  97.     // release all device resources before resetting.  Likewise, if you don't handle the 
  98.     // device created/destroyed callbacks then the sample framework won't be able to 
  99.     // recreate your device resources.
  100.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  101.     DXUTSetCallbackDeviceReset( OnResetDevice );
  102.     DXUTSetCallbackDeviceLost( OnLostDevice );
  103.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  104.     DXUTSetCallbackMsgProc( MsgProc );
  105.     DXUTSetCallbackKeyboard( KeyboardProc );
  106.     DXUTSetCallbackFrameRender( OnFrameRender );
  107.     DXUTSetCallbackFrameMove( OnFrameMove );
  108.  
  109.     // Show the cursor and clip it when in full screen
  110.     DXUTSetCursorSettings( true, true );
  111.  
  112.     InitApp();
  113.  
  114.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  115.     // device for the application. Calling each of these functions is optional, but they
  116.     // allow you to set several options which control the behavior of the framework.
  117.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  118.     DXUTCreateWindow( L"MeshFromOBJ" );
  119.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  120.  
  121.     // Pass control to the sample framework for handling the message pump and 
  122.     // dispatching render calls. The sample framework will call your FrameMove 
  123.     // and FrameRender callback when there is idle time between handling window messages.
  124.     DXUTMainLoop();
  125.  
  126.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  127.     // appropriate callback functions and therefore don't require any cleanup code here.
  128.  
  129.     return DXUTGetExitCode();
  130. }
  131.  
  132.  
  133. //--------------------------------------------------------------------------------------
  134. // Initialize the app 
  135. //--------------------------------------------------------------------------------------
  136. void InitApp()
  137. {
  138.     // Initialize dialogs
  139.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  140.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  141.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  142.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  143.  
  144.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10; 
  145.  
  146.     // Title font for comboboxes
  147.     g_SampleUI.SetFont( 1, L"Arial", 14, FW_BOLD );
  148.     CDXUTElement* pElement = g_SampleUI.GetDefaultElement( DXUT_CONTROL_STATIC, 0 );
  149.     pElement->iFont = 1;
  150.     pElement->dwTextFormat = DT_LEFT | DT_BOTTOM;
  151.  
  152.     g_SampleUI.AddStatic( IDC_STATIC, L"(S)ubset", 20, 0, 105, 25 );
  153.     g_SampleUI.AddComboBox( IDC_SUBSET, 20, 25, 140, 24, 'S' );
  154.     g_SampleUI.AddButton(IDC_SAVETOX, L"Save Mesh To X file",  20, 50,  140, 24, 'X');
  155.     
  156. }
  157.  
  158.  
  159.  
  160.  
  161.  
  162. //--------------------------------------------------------------------------------------
  163. // Called during device initialization, this code checks the device for some 
  164. // minimum set of capabilities, and rejects those that don't pass by returning false.
  165. //--------------------------------------------------------------------------------------
  166. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  167.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  168. {
  169.     // No fallback defined by this app, so reject any device that 
  170.     // doesn't support at least ps1.4
  171.     if( pCaps->PixelShaderVersion < D3DPS_VERSION(1,4) )
  172.         return false;
  173.  
  174.     // Skip backbuffer formats that don't support alpha blending
  175.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  176.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  177.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  178.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  179.         return false;
  180.  
  181.     return true;
  182. }
  183.  
  184.  
  185. //--------------------------------------------------------------------------------------
  186. // This callback function is called immediately before a device is created to allow the 
  187. // application to modify the device settings. The supplied pDeviceSettings parameter 
  188. // contains the settings that the framework has selected for the new device, and the 
  189. // application can make any desired changes directly to this structure.  Note however that 
  190. // the sample framework will not correct invalid device settings so care must be taken 
  191. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  192. //--------------------------------------------------------------------------------------
  193. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  194. {
  195.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  196.     // then switch to SWVP.
  197.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  198.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  199.     {
  200.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  201.     }
  202.     else
  203.     {
  204.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  205.     }
  206.  
  207.     // This application is designed to work on a pure device by not using 
  208.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  209.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  210.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  211.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  212.  
  213.     // Debugging vertex shaders requires either REF or software vertex processing 
  214.     // and debugging pixel shaders requires REF.  
  215. #ifdef DEBUG_VS
  216.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  217.     {
  218.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  219.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  220.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  221.     }
  222. #endif
  223. #ifdef DEBUG_PS
  224.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  225. #endif
  226.  
  227.     // Enable anti-aliasing for HAL devices which support it
  228.     CD3DEnumeration* pEnum = DXUTGetEnumeration(); 
  229.     CD3DEnumDeviceSettingsCombo* pCombo = pEnum->GetDeviceSettingsCombo( pDeviceSettings );
  230.     
  231.     if( pDeviceSettings->DeviceType == D3DDEVTYPE_HAL && 
  232.         pCombo->multiSampleTypeList.Contains( D3DMULTISAMPLE_4_SAMPLES ) )
  233.     {
  234.         pDeviceSettings->pp.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
  235.         pDeviceSettings->pp.MultiSampleQuality = 0;
  236.     }
  237. }
  238.  
  239.  
  240. //--------------------------------------------------------------------------------------
  241. // This callback function will be called immediately after the Direct3D device has been 
  242. // created, which will happen during application initialization and windowed/full screen 
  243. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  244. // resources need to be reloaded whenever the device is destroyed. Resources created  
  245. // here should be released in the OnDestroyDevice callback. 
  246. //--------------------------------------------------------------------------------------
  247. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  248. {
  249.     HRESULT hr;
  250.     WCHAR str[MAX_PATH];
  251.     
  252.     // Initialize the font
  253.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  254.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  255.                          L"Arial", &g_pFont ) );
  256.  
  257.     // Create the mesh and load it with data already gathered from a file
  258.     V_RETURN( g_MeshLoader.Create( pd3dDevice, L"media\\cup.obj" ) );
  259.  
  260.     // Add the identified material subsets to the UI
  261.     CDXUTComboBox* pComboBox = g_SampleUI.GetComboBox( IDC_SUBSET ); 
  262.     pComboBox->RemoveAllItems();
  263.     pComboBox->AddItem( L"All", (void*)(INT_PTR) -1 );
  264.     
  265.     for( UINT i=0; i < g_MeshLoader.GetNumMaterials(); i++ )
  266.     {
  267.         Material* pMaterial = g_MeshLoader.GetMaterial( i );
  268.         pComboBox->AddItem( pMaterial->strName, (void*)(INT_PTR) i );
  269.     }
  270.     
  271.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  272.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  273.     // processing, and debugging pixel shaders requires REF.  The 
  274.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  275.     // shader debugger.  It enables source level debugging, prevents instruction 
  276.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  277.     // against the next higher available software target, which ensures that the 
  278.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  279.     // flags will cause slower rendering since the shaders will be unoptimized and 
  280.     // forced into software.  See the DirectX documentation for more information about 
  281.     // using the shader debugger.
  282.     DWORD dwShaderFlags = 0;
  283.     #ifdef DEBUG_VS
  284.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  285.     #endif
  286.     #ifdef DEBUG_PS
  287.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  288.     #endif
  289.  
  290.     // Read the D3DX effect file
  291.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"MeshFromOBJ.fx" ) );
  292.  
  293.     // If this fails, there should be debug output as to 
  294.     // they the .fx file failed to compile
  295.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  296.                                         NULL, &g_pEffect, NULL ) );
  297.  
  298.     // Cache the effect handles
  299.     g_hAmbient = g_pEffect->GetParameterBySemantic( 0, "Ambient" );
  300.     g_hDiffuse = g_pEffect->GetParameterBySemantic( 0, "Diffuse" );
  301.     g_hSpecular = g_pEffect->GetParameterBySemantic( 0, "Specular" );
  302.     g_hOpacity = g_pEffect->GetParameterBySemantic( 0, "Opacity" );
  303.     g_hSpecularPower = g_pEffect->GetParameterBySemantic( 0, "SpecularPower" );
  304.     g_hLightColor = g_pEffect->GetParameterBySemantic( 0, "LightColor" );
  305.     g_hLightPosition = g_pEffect->GetParameterBySemantic( 0, "LightPosition" );
  306.     g_hCameraPosition = g_pEffect->GetParameterBySemantic( 0, "CameraPosition" );
  307.     g_hTexture = g_pEffect->GetParameterBySemantic( 0, "Texture" );      
  308.     g_hTime = g_pEffect->GetParameterBySemantic( 0, "Time" );
  309.     g_hWorld = g_pEffect->GetParameterBySemantic( 0, "World" );
  310.     g_hWorldViewProjection = g_pEffect->GetParameterBySemantic( 0, "WorldViewProjection" );
  311.  
  312.     // Setup the camera's view parameters
  313.     D3DXVECTOR3 vecEye(2.0f, 1.0f, 0.0f);
  314.     D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  315.     g_Camera.SetViewParams( &vecEye, &vecAt );
  316.  
  317.     return S_OK;
  318. }
  319.  
  320.  
  321.  
  322.  
  323.  
  324. //--------------------------------------------------------------------------------------
  325. // This callback function will be called immediately after the Direct3D device has been 
  326. // reset, which will happen after a lost device scenario. This is the best location to 
  327. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  328. // the device is lost. Resources created here should be released in the OnLostDevice 
  329. // callback. 
  330. //--------------------------------------------------------------------------------------
  331. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  332.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  333. {
  334.     HRESULT hr;
  335.  
  336.     if( g_pFont )
  337.         V_RETURN( g_pFont->OnResetDevice() );
  338.     if( g_pEffect )
  339.         V_RETURN( g_pEffect->OnResetDevice() );
  340.  
  341.     // Store the correct technique handles for each material
  342.     for( UINT i=0; i < g_MeshLoader.GetNumMaterials(); i++ )
  343.     {
  344.         Material* pMaterial = g_MeshLoader.GetMaterial( i );
  345.         
  346.         const char* strTechnique;
  347.  
  348.         if( pMaterial->pTexture && pMaterial->bSpecular )
  349.             strTechnique = "TexturedSpecular";
  350.         else if( pMaterial->pTexture && !pMaterial->bSpecular )
  351.             strTechnique = "TexturedNoSpecular";
  352.         else if( !pMaterial->pTexture && pMaterial->bSpecular )
  353.             strTechnique = "Specular";
  354.         else if( !pMaterial->pTexture && !pMaterial->bSpecular )
  355.             strTechnique = "NoSpecular";
  356.  
  357.         pMaterial->hTechnique = g_pEffect->GetTechniqueByName( strTechnique );
  358.     }
  359.     
  360.     // Create a sprite to help batch calls when drawing many lines of text
  361.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  362.  
  363.     // Setup the camera's projection parameters
  364.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  365.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  366.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  367.     
  368.  
  369.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  370.     g_HUD.SetSize( 170, 170 );
  371.     g_HUD.Refresh();
  372.  
  373.     g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width-170, pBackBufferSurfaceDesc->Height-350 );
  374.     g_SampleUI.SetSize( 170, 300 );
  375.     g_SampleUI.Refresh();
  376.  
  377.     return S_OK;
  378. }
  379.  
  380.  
  381. //--------------------------------------------------------------------------------------
  382. // This callback function will be called once at the beginning of every frame. This is the
  383. // best location for your application to handle updates to the scene, but is not 
  384. // intended to contain actual rendering calls, which should instead be placed in the 
  385. // OnFrameRender callback.  
  386. //--------------------------------------------------------------------------------------
  387. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  388. {
  389.     // Update the camera's position based on user input 
  390.     g_Camera.FrameMove( fElapsedTime );
  391. }
  392.  
  393.  
  394. //--------------------------------------------------------------------------------------
  395. // This callback function will be called at the end of every frame to perform all the 
  396. // rendering calls for the scene, and it will also be called if the window needs to be 
  397. // repainted. After this function has returned, the sample framework will call 
  398. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  399. //--------------------------------------------------------------------------------------
  400. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  401. {
  402.     HRESULT hr;
  403.     D3DXMATRIXA16 mWorld;
  404.     D3DXMATRIXA16 mView;
  405.     D3DXMATRIXA16 mProj;
  406.     D3DXMATRIXA16 mWorldViewProjection;
  407.     
  408.     
  409.     // Clear the render target and the zbuffer 
  410.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 141, 153, 191), 1.0f, 0) );
  411.  
  412.     // Render the scene
  413.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  414.     {
  415.         // Get the projection & view matrix from the camera class
  416.         mWorld = *g_Camera.GetWorldMatrix();       
  417.         mView = *g_Camera.GetViewMatrix();
  418.         mProj = *g_Camera.GetProjMatrix();       
  419.         
  420.         mWorldViewProjection = mWorld * mView * mProj;
  421.  
  422.         // Update the effect's variables. 
  423.         V( g_pEffect->SetMatrix( g_hWorldViewProjection, &mWorldViewProjection ) );
  424.         V( g_pEffect->SetMatrix( g_hWorld, &mWorld ) );
  425.         V( g_pEffect->SetFloat( g_hTime, (float)fTime ) );
  426.         V( g_pEffect->SetValue( g_hCameraPosition, g_Camera.GetEyePt(), sizeof(D3DXVECTOR3) ) );
  427.  
  428.         UINT iCurSubset = (UINT)(INT_PTR) g_SampleUI.GetComboBox( IDC_SUBSET )->GetSelectedData();
  429.  
  430.         // A subset of -1 was arbitrarily chosen to represent all subsets
  431.         if( iCurSubset == -1 )
  432.         {
  433.             // Iterate through subsets, changing material properties for each
  434.             for( UINT iSubset = 0; iSubset < g_MeshLoader.GetNumMaterials(); iSubset++ )
  435.             {
  436.                 RenderSubset( iSubset );
  437.             }
  438.         }
  439.         else
  440.         {
  441.             RenderSubset( iCurSubset );
  442.         }
  443.  
  444.         RenderText();
  445.         V( g_HUD.OnRender( fElapsedTime ) );
  446.         V( g_SampleUI.OnRender( fElapsedTime ) );
  447.  
  448.         V( pd3dDevice->EndScene() );
  449.     }
  450. }
  451.  
  452.  
  453. //--------------------------------------------------------------------------------------
  454. void RenderSubset( UINT iSubset )
  455. {
  456.     HRESULT hr;
  457.     UINT iPass, cPasses;
  458.    
  459.     // Retrieve the ID3DXMesh pointer and current material from the MeshLoader helper
  460.     ID3DXMesh* pMesh = g_MeshLoader.GetMesh();
  461.     Material* pMaterial = g_MeshLoader.GetMaterial( iSubset );
  462.  
  463.     // Set the lighting variables and texture for the current material
  464.     V( g_pEffect->SetValue( g_hAmbient, pMaterial->vAmbient, sizeof(D3DXVECTOR3) ) );
  465.     V( g_pEffect->SetValue( g_hDiffuse, pMaterial->vDiffuse, sizeof(D3DXVECTOR3) ) );
  466.     V( g_pEffect->SetValue( g_hSpecular, pMaterial->vSpecular, sizeof(D3DXVECTOR3) ) );
  467.     V( g_pEffect->SetTexture( g_hTexture, pMaterial->pTexture ) );
  468.     V( g_pEffect->SetFloat( g_hOpacity, pMaterial->fAlpha ) );
  469.     V( g_pEffect->SetInt( g_hSpecularPower, pMaterial->nShininess ) );
  470.  
  471.     V( g_pEffect->SetTechnique( pMaterial->hTechnique ) );
  472.     V( g_pEffect->Begin(&cPasses, 0) );
  473.  
  474.     for (iPass = 0; iPass < cPasses; iPass++)
  475.     {
  476.         V( g_pEffect->BeginPass(iPass) );
  477.  
  478.         // The effect interface queues up the changes and performs them 
  479.         // with the CommitChanges call. You do not need to call CommitChanges if 
  480.         // you are not setting any parameters between the BeginPass and EndPass.
  481.         // V( g_pEffect->CommitChanges() );
  482.  
  483.         // Render the mesh with the applied technique
  484.         V( pMesh->DrawSubset( iSubset ) );
  485.  
  486.         V( g_pEffect->EndPass() );
  487.     }
  488.     V( g_pEffect->End() );
  489. }
  490.  
  491. //--------------------------------------------------------------------------------------
  492. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  493. // efficient text rendering.
  494. //--------------------------------------------------------------------------------------
  495. void RenderText()
  496. {
  497.     // The helper object simply helps keep track of text position, and color
  498.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  499.     // If NULL is passed in as the sprite object, then it will work however the 
  500.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  501.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  502.  
  503.     // Output statistics
  504.     txtHelper.Begin();
  505.     txtHelper.SetInsertionPos( 5, 5 );
  506.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  507.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  508.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  509.  
  510.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  511.     txtHelper.DrawTextLine( g_strFileSaveMessage );
  512.     
  513.     // Draw help
  514.     if( g_bShowHelp )
  515.     {
  516.         const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  517.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*5 );
  518.         txtHelper.SetForegroundColor( D3DCOLOR_ARGB( 200, 50, 50, 50 ) );
  519.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  520.  
  521.         txtHelper.SetInsertionPos( 20, pd3dsdBackBuffer->Height-15*4 );
  522.         txtHelper.DrawTextLine( L"Rotate model: Left mouse button\n"
  523.                                 L"Rotate camera: Right mouse button\n"
  524.                                 L"Zoom camera: Mouse wheel scroll\n" );
  525.  
  526.         txtHelper.SetInsertionPos( 250, pd3dsdBackBuffer->Height-15*4 );
  527.         txtHelper.DrawTextLine( L"Hide help: F1\n"); 
  528.         txtHelper.DrawTextLine( L"Quit: ESC\n" );
  529.     }
  530.     else
  531.     {
  532.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  533.         txtHelper.DrawTextLine( L"Press F1 for help" );
  534.     }
  535.  
  536.     txtHelper.End();
  537. }
  538.  
  539.  
  540. //--------------------------------------------------------------------------------------
  541. // Before handling window messages, the sample framework passes incoming windows 
  542. // messages to the application through this callback function. If the application sets 
  543. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  544. //--------------------------------------------------------------------------------------
  545. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  546. {
  547.     // Give the dialogs a chance to handle the message first
  548.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  549.     if( *pbNoFurtherProcessing )
  550.         return 0;
  551.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  552.     if( *pbNoFurtherProcessing )
  553.         return 0;
  554.  
  555.     // Pass all remaining windows messages to camera so it can respond to user input
  556.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  557.  
  558.     return 0;
  559. }
  560.  
  561.  
  562. //--------------------------------------------------------------------------------------
  563. // As a convenience, the sample framework inspects the incoming windows messages for
  564. // keystroke messages and decodes the message parameters to pass relevant keyboard
  565. // messages to the application.  The framework does not remove the underlying keystroke 
  566. // messages, which are still passed to the application's MsgProc callback.
  567. //--------------------------------------------------------------------------------------
  568. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  569. {
  570.     if( bKeyDown )
  571.     {
  572.         switch( nChar )
  573.         {
  574.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  575.         }
  576.     }
  577. }
  578.  
  579.  
  580. //--------------------------------------------------------------------------------------
  581. // Handles the GUI events
  582. //--------------------------------------------------------------------------------------
  583. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  584. {
  585.     switch( nControlID )
  586.     {
  587.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  588.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  589.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  590.         case IDC_SAVETOX:          SaveMeshToXFile(); break;    
  591.     }
  592. }
  593.  
  594.  
  595. //--------------------------------------------------------------------------------------
  596. // This callback function will be called immediately after the Direct3D device has 
  597. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  598. // in the OnResetDevice callback should be released here, which generally includes all 
  599. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  600. // information about lost devices.
  601. //--------------------------------------------------------------------------------------
  602. void CALLBACK OnLostDevice()
  603. {
  604.     if( g_pFont )
  605.         g_pFont->OnLostDevice();
  606.     if( g_pEffect )
  607.         g_pEffect->OnLostDevice();
  608.  
  609.     SAFE_RELEASE(g_pTextSprite);
  610. }
  611.  
  612.  
  613. //--------------------------------------------------------------------------------------
  614. // This callback function will be called immediately after the Direct3D device has 
  615. // been destroyed, which generally happens as a result of application termination or 
  616. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  617. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  618. //--------------------------------------------------------------------------------------
  619. void CALLBACK OnDestroyDevice()
  620. {
  621.     SAFE_RELEASE( g_pEffect );
  622.     SAFE_RELEASE( g_pFont );
  623.     
  624.     g_MeshLoader.Destroy();
  625. }
  626.  
  627. //--------------------------------------------------------------------------------------
  628. // Saves the mesh to X-file
  629. //--------------------------------------------------------------------------------------
  630. void SaveMeshToXFile()
  631. {
  632.     HRESULT hr;
  633.  
  634.     // Fill out D3DXMATERIAL structures
  635.     UINT numMaterials = g_MeshLoader.GetNumMaterials();
  636.     D3DXMATERIAL *pMaterials = new D3DXMATERIAL[numMaterials];
  637.     char *pStrTexture = new char[MAX_PATH * numMaterials];
  638.     if ((pMaterials != NULL) && (pStrTexture != NULL))
  639.     {
  640.         for( UINT i=0; i < g_MeshLoader.GetNumMaterials(); i++ )
  641.         {
  642.             Material* pMat = g_MeshLoader.GetMaterial( i );
  643.             if (pMat != NULL)
  644.             {
  645.                 pMaterials[i].MatD3D.Ambient.r = pMat->vAmbient.x;
  646.                 pMaterials[i].MatD3D.Ambient.g = pMat->vAmbient.y;
  647.                 pMaterials[i].MatD3D.Ambient.b = pMat->vAmbient.z;
  648.                 pMaterials[i].MatD3D.Ambient.a = pMat->fAlpha;
  649.  
  650.                 pMaterials[i].MatD3D.Diffuse.r = pMat->vDiffuse.x;
  651.                 pMaterials[i].MatD3D.Diffuse.g = pMat->vDiffuse.y;
  652.                 pMaterials[i].MatD3D.Diffuse.b = pMat->vDiffuse.z;
  653.                 pMaterials[i].MatD3D.Diffuse.a = pMat->fAlpha;
  654.  
  655.                 pMaterials[i].MatD3D.Specular.r = pMat->vSpecular.x;
  656.                 pMaterials[i].MatD3D.Specular.g = pMat->vSpecular.y;
  657.                 pMaterials[i].MatD3D.Specular.b = pMat->vSpecular.z;
  658.                 pMaterials[i].MatD3D.Specular.a = pMat->fAlpha;
  659.  
  660.                 pMaterials[i].MatD3D.Emissive.r = 0;
  661.                 pMaterials[i].MatD3D.Emissive.g = 0;
  662.                 pMaterials[i].MatD3D.Emissive.b = 0;
  663.                 pMaterials[i].MatD3D.Emissive.a = 0;
  664.  
  665.                 pMaterials[i].MatD3D.Power = (float)pMat->nShininess;
  666.  
  667.                 WideCharToMultiByte( CP_ACP, 0, pMat->strTexture, -1, (pStrTexture + i*MAX_PATH), MAX_PATH, NULL, NULL );
  668.                 pMaterials[i].pTextureFilename = (pStrTexture + i*MAX_PATH);
  669.             }
  670.         
  671.         }
  672.         
  673.         // Write to file in same directory where the .obj file was found
  674.         WCHAR strBuf[ MAX_PATH ];
  675.         _snwprintf( strBuf, MAX_PATH-1, L"%s\\%s", g_MeshLoader.GetMediaDirectory(), L"MeshFromOBJ.x" );
  676.         hr = D3DXSaveMeshToX( strBuf, g_MeshLoader.GetMesh(), NULL, 
  677.                               pMaterials, NULL, numMaterials, 
  678.                               D3DXF_FILEFORMAT_TEXT );
  679.  
  680.         if( SUCCEEDED(hr) )
  681.         {
  682.             _snwprintf( g_strFileSaveMessage, MAX_PATH-1, L"Created %s", strBuf );
  683.         }
  684.         else
  685.         {
  686.             DXTRACE_ERR( L"SaveMeshToXFile()::D3DXSaveMeshToX", hr );
  687.             _snwprintf( g_strFileSaveMessage, MAX_PATH-1, L"Error creating %s, check debug output", strBuf );      
  688.         }
  689.  
  690.         
  691.     }
  692. }
  693.  
  694.  
  695.  
  696.